/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.api.runtime.process.conf;

import com.je.bpm.api.runtime.process.ProcessOperatorServiceImpl;
import com.je.bpm.api.runtime.process.conf.impl.ProcessRuntimeConfigurationImpl;
import com.je.bpm.api.runtime.process.event.impl.*;
import com.je.bpm.api.runtime.process.event.internal.*;
import com.je.bpm.api.runtime.process.impl.*;
import com.je.bpm.api.runtime.process.operator.*;
import com.je.bpm.api.runtime.process.signal.SignalPayloadEventListener;
import com.je.bpm.api.runtime.process.spring.ProcessVariablesInitiator;
import com.je.bpm.api.runtime.shared.conf.CommonRuntimeAutoConfiguration;
import com.je.bpm.api.runtime.shared.impl.ApiButtonConverter;
import com.je.bpm.api.runtime.task.impl.ApiTaskButtonConverter;
import com.je.bpm.engine.HistoryService;
import com.je.bpm.engine.RepositoryService;
import com.je.bpm.engine.RuntimeService;
import com.je.bpm.engine.TaskService;
import com.je.bpm.engine.delegate.event.ActivitiEventType;
import com.je.bpm.engine.impl.event.EventSubscriptionPayloadMappingProvider;
import com.je.bpm.engine.impl.util.ProcessInstanceHelper;
import com.je.bpm.engine.upcoming.ActivitiUpcomingRun;
import com.je.bpm.model.process.events.*;
import com.je.bpm.runtime.process.ProcessOperatorService;
import com.je.bpm.runtime.process.conf.ProcessRuntimeConfiguration;
import com.je.bpm.runtime.process.event.listener.BPMNElementEventListener;
import com.je.bpm.runtime.process.event.listener.ProcessRuntimeEventListener;
import com.je.bpm.runtime.process.operator.*;
import com.je.bpm.runtime.shared.RemoteCallServeManager;
import com.je.bpm.runtime.shared.event.listener.VariableEventListener;
import com.je.bpm.runtime.shared.identity.UserRoleManager;
import com.je.bpm.spring.process.ProcessExtensionService;
import com.je.bpm.spring.process.variable.VariableParsingService;
import com.je.bpm.spring.process.variable.VariableValidationService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

import static java.util.Collections.emptyList;

@Configuration
@AutoConfigureAfter(CommonRuntimeAutoConfiguration.class)
public class ProcessRuntimeAutoConfiguration {

    @Bean
    public ProcessOperatorService processOperatorService(ProcessInstanceActiveOperator processActiveOperator, ProcessInstanceCancelOperator processCancelOperator,
                                                         ProcessInstanceHangOperator processHangOperator, ProcessInstanceInvalidOperator processInvalidOperator,
                                                         ProcessEmptyStartOperator processStartOperator, ProcessEmptySponsorOperator processSponsorOperator,
                                                         ProcessDefinitionGetOperator getProcessDefinitionOperator,
                                                         ProcessModelSaveOperator processModelSaveOperator,
                                                         ProcessGetButtonOperator processGetButtonOperator,
                                                         ProcessGetNextElementOperator processGetNextElementOperator,
                                                         ProcessGetGobackElementOperator processGetGobackElementOperator,
                                                         ProcessGetDelegateElementOperator processGetDelegateElementOperator,
                                                         ProcessGetDismissElementOperator processGetDismissElementOperator,
                                                         ProcessGetCirculatedInfoOperator processGetCirculatedInfoOperator,
                                                         ProcessGetNextElementAssigneeOperator processGetNextElementAssigneeOperator) {
        return new ProcessOperatorServiceImpl(processActiveOperator, processCancelOperator, processHangOperator,
                processInvalidOperator, processStartOperator, processSponsorOperator, getProcessDefinitionOperator,
                processModelSaveOperator, processGetButtonOperator, processGetNextElementOperator, processGetGobackElementOperator,
                processGetDelegateElementOperator, processGetDismissElementOperator, processGetCirculatedInfoOperator, processGetNextElementAssigneeOperator);
    }

    @Bean
    public ApiProcessButtonConverter apiProcessButtonConverter() {
        return new ApiProcessButtonConverter();
    }

    @Bean
    public ApiButtonConverter apButtonConverter(ApiProcessButtonConverter apiProcessButtonConverter, ApiTaskButtonConverter apiTaskButtonConverter) {
        return new ApiButtonConverter(apiProcessButtonConverter, apiTaskButtonConverter);
    }

    @Bean
    public ApiFormButtonConfigConverter apiFormButtonConfigConverter() {
        return new ApiFormButtonConfigConverter();
    }

    @Bean
    public ApiFormFieldConfigConverter apiFormFieldConfigConverter() {
        return new ApiFormFieldConfigConverter();
    }

    @Bean
    public ApiFormChildFuncConfigConverter apiFormChildFuncConfigConverter() {
        return new ApiFormChildFuncConfigConverter();
    }

    @Bean
    public ApiFormConfigConverter apiFormConfigConverter(ApiFormButtonConfigConverter apiFormButtonConfigConverter,
                                                         ApiFormFieldConfigConverter apiFormFieldConfigConverter,
                                                         ApiFormChildFuncConfigConverter apiFormChildFuncConfigConverter) {
        return new ApiFormConfigConverter(apiFormButtonConfigConverter, apiFormFieldConfigConverter, apiFormChildFuncConfigConverter);
    }

    @Bean
    public ApiWorkFlowConfigConverter apiWorkFlowConfigConverter() {
        return new ApiWorkFlowConfigConverter();
    }

    @Bean
    public ApiTaskButtonConverter apiTaskButtonConverter() {
        return new ApiTaskButtonConverter();
    }

    @Bean
    public APIProcessConfigConverter apiProcessConfigConverter() {
        return new APIProcessConfigConverter();
    }

    @Bean
    public APIProcessModelConverter apiProcessModelConverter() {
        return new APIProcessModelConverter();
    }

    @Bean
    public ProcessModelSaveOperator processModelSaveOperator(APIProcessModelConverter apiProcessModelConverter, RepositoryService repositoryService) {
        return new ProcessModelSaveOrUpdateOperatorImpl(apiProcessModelConverter, repositoryService);
    }

    @Bean
    public ProcessDefinitionHangOperator processDefinitionHangOperator(APIProcessDefinitionConverter processDefinitionConverter,
                                                                       APIProcessConfigConverter processConfigConverter,
                                                                       ApiProcessButtonConverter processButtonConverter,
                                                                       RepositoryService repositoryService) {
        return new ProcessDefinitionHangOperatorImpl(processDefinitionConverter, processConfigConverter, processButtonConverter, repositoryService);
    }

    @Bean
    public ProcessDefinitionActiveOperator processDefinitionActiveOperator(APIProcessDefinitionConverter processDefinitionConverter,
                                                                           APIProcessConfigConverter processConfigConverter,
                                                                           ApiProcessButtonConverter processButtonConverter,
                                                                           RepositoryService repositoryService) {
        return new ProcessDefinitionActiveOperatorImpl(processDefinitionConverter, processConfigConverter, processButtonConverter, repositoryService);
    }

    @Bean
    public ProcessDefinitionGetListOperator processDefinitionGetListOperator(APIProcessDefinitionConverter processDefinitionConverter, RepositoryService repositoryService) {
        return new ProcessDefinitionGetListOperatorImpl(processDefinitionConverter, repositoryService);
    }

    @Bean
    public ProcessDefinitionGetOperator getProcessDefinitionOperator(APIProcessDefinitionConverter apiProcessDefinitionConverter,
                                                                     APIProcessConfigConverter apiProcessConfigConverter,
                                                                     ApiProcessButtonConverter apiProcessButtonConverter,
                                                                     RepositoryService repositoryService) {
        return new ProcessDefinitionGetOperatorImpl(apiProcessDefinitionConverter, apiProcessConfigConverter,
                apiProcessButtonConverter, repositoryService);
    }

    @Bean
    public ProcessDeploymentDeleteOperator processDeploymentDeleteOperator(RepositoryService repositoryService) {
        return new ProcessDeploymentDeleteOperatorImpl(repositoryService);
    }

    @Bean
    public ProcessDeploymentGetListOperator processDeploymentGetListOperator(APIDeploymentConverter apiDeploymentConverter,
                                                                             RepositoryService repositoryService) {
        return new ProcessDeploymentGetListOperatorImpl(apiDeploymentConverter, repositoryService);
    }

    @Bean
    public ProcessDeploymentGetOperator processDeploymentGetOperator(APIDeploymentConverter apiDeploymentConverter,
                                                                     RepositoryService repositoryService) {
        return new ProcessDeploymentGetOperatorImpl(apiDeploymentConverter, repositoryService);
    }

    @Bean
    public ProcessModelDeleteOperator processModelDeleteOperator(RepositoryService repositoryService) {
        return new ProcessModelDeleteOperatorImpl(repositoryService);
    }

    @Bean
    public ProcessModelGetListOperator processModelGetListOperator(APIProcessModelConverter apiProcessModelConverter, RepositoryService repositoryService) {
        return new ProcessModelGetListOperatorImpl(apiProcessModelConverter, repositoryService);
    }

    @Bean
    public ProcessModelGetOperator processModelGetOperator(APIProcessModelConverter apiProcessModelConverter, RepositoryService repositoryService) {
        return new ProcessModelGetOperatorImpl(apiProcessModelConverter, repositoryService);
    }

    @Bean
    public ProcessModelDeployOperator processModelDeployOperator(RepositoryService repositoryService) {
        return new ProcessModelDeployOperatorImpl(repositoryService);
    }


    @Bean
    public ProcessInstanceActiveOperator processActiveOperator(APIProcessInstanceConverter processInstanceConverter, RuntimeService runtimeService) {
        return new ProcessInstanceActiveOperatorImpl(processInstanceConverter, runtimeService);
    }

    @Bean
    public ProcessGetNextElementOperator processGetNextElementOperator(RepositoryService repositoryService, RuntimeService runtimeService, TaskService taskService) {
        return new ProcessGetNextElementOperatorImpl(repositoryService, runtimeService, taskService);
    }

    @Bean
    public ProcessGetNextElementAssigneeOperator processGetNextElementAssigneeOperator(RepositoryService repositoryService, RuntimeService runtimeService) {
        return new ProcessGetNextElementAssigneeOperatorImpl(repositoryService, runtimeService);
    }

    @Bean
    public ProcessGetCirculatedInfoOperator processGetCirculatedInfoOperator(RepositoryService repositoryService, RuntimeService runtimeService, TaskService taskService) {
        return new ProcessGetCirculatedInfoOperatorImpl(repositoryService, runtimeService, taskService);
    }

    @Bean
    public ProcessGetGobackElementOperator processGetGobackElementOperator(RepositoryService repositoryService, RuntimeService runtimeService, TaskService taskService) {
        return new ProcessGetGobackElementOperatorImpl(repositoryService, runtimeService, taskService);
    }

    @Bean
    public ProcessGetDismissElementOperator processGetDismissElementOperator(APIProcessDismissElementConverter apiProcessDismissElementConverter, RuntimeService runtimeService) {
        return new ProcessGetDismissElementOperatorImpl(apiProcessDismissElementConverter, runtimeService);
    }

    @Bean
    public ProcessInstanceCancelOperator processCancelOperator(APIProcessDefinitionConverter processDefinitionConverter, APIProcessConfigConverter processConfigConverter,
                                                               ApiProcessButtonConverter processButtonConverter,
                                                               RepositoryService repositoryService,
                                                               RuntimeService runtimeService, RemoteCallServeManager remoteCallServeManager,
                                                               ActivitiUpcomingRun activitiUpcomingRun) {
        return new ProcessInstanceCancelOperatorImpl(processDefinitionConverter, processConfigConverter, processButtonConverter, repositoryService, runtimeService, remoteCallServeManager,
                activitiUpcomingRun);
    }

    @Bean
    public ProcessInstanceHangOperator processHangOperator(APIProcessInstanceConverter processInstanceConverter, RuntimeService runtimeService) {
        return new ProcessInstanceHangOperatorImpl(processInstanceConverter, runtimeService);
    }

    @Bean
    public ProcessInstanceInvalidOperator processInvalidOperator(APIProcessDefinitionConverter processDefinitionConverter, APIProcessConfigConverter processConfigConverter,
                                                                 ApiProcessButtonConverter processButtonConverter, RepositoryService repositoryService,
                                                                 RuntimeService runtimeService, RemoteCallServeManager remoteCallServeManager) {
        return new ProcessInstanceInvalidOperatorImpl(processDefinitionConverter, processConfigConverter, processButtonConverter, repositoryService, runtimeService, remoteCallServeManager);
    }

    @Bean
    public ProcessEmptySponsorOperator processSponsorOperator(APIProcessInstanceConverter processInstanceConverter, RuntimeService runtimeService, RemoteCallServeManager remoteCallServeManager, ProcessInstanceHelper processInstanceHelper) {
        return new ProcessEmptySponsorOperatorImpl(processInstanceConverter, runtimeService, remoteCallServeManager, processInstanceHelper);
    }

    @Bean
    public ProcessEmptyStartOperator processStartOperator(APIProcessInstanceConverter processInstanceConverter, RuntimeService runtimeService, RemoteCallServeManager remoteCallServeManager, RepositoryService repositoryService, ProcessInstanceHelper processInstanceHelper) {
        return new ProcessEmptyStartOperatorImpl(processInstanceConverter, runtimeService, remoteCallServeManager, repositoryService, processInstanceHelper);
    }

    @Bean
    public ProcessGetButtonOperator processGetInitialButtonOperator(ApiButtonConverter apiButtonConverter, RepositoryService repositoryService,
                                                                    RuntimeService runtimeService, ApiFormConfigConverter apiFormConfigConverter,
                                                                    ApiWorkFlowConfigConverter apiWorkFlowConfigConverter,
                                                                    UserRoleManager userRoleManager, HistoryService historyService) {
        return new ProcessGetButtonOperatorImpl(apiButtonConverter, repositoryService, runtimeService, apiFormConfigConverter, apiWorkFlowConfigConverter, userRoleManager, historyService);
    }

    @Bean
    public ProcessGetDelegateElementOperator processGetDelegateElementOperator(RepositoryService repositoryService, RuntimeService runtimeService,
                                                                               TaskService taskService) {
        return new ProcessGetDelegateElementOperatorImpl(repositoryService, runtimeService, taskService);
    }


    /**
     * Creates default SignalPayloadEventListener bean if no existing bean found in ApplicationContext.
     */
    @Bean
    @ConditionalOnMissingBean(SignalPayloadEventListener.class)
    public SignalPayloadEventListener signalPayloadEventListener(RuntimeService runtimeService) {
        return new RuntimeSignalPayloadEventListener(runtimeService);
    }

    @Bean
    @ConditionalOnMissingBean(EventSubscriptionPayloadMappingProvider.class)
    public EventSubscriptionPayloadMappingProvider eventSubscriptionPayloadMappingProvider(ExtensionsVariablesMappingProvider variablesMappingProvider) {
        return new EventSubscriptionVariablesMappingProvider(variablesMappingProvider);
    }

    @Bean
    @ConditionalOnMissingBean
    public MessageSubscriptionConverter messageEventSubscriptionConverter() {
        return new MessageSubscriptionConverter();
    }

    @Bean
    @ConditionalOnMissingBean
    public StartMessageSubscriptionConverter startMessageEventSubscriptionConverter() {
        return new StartMessageSubscriptionConverter();
    }

    @Bean
    @ConditionalOnMissingBean
    public APIProcessDefinitionConverter apiProcessDefinitionConverter(RepositoryService repositoryService) {
        return new APIProcessDefinitionConverter(repositoryService);
    }

    @Bean
    @ConditionalOnMissingBean
    public ProcessVariablesInitiator processVariablesInitiator(ProcessExtensionService processExtensionService, VariableParsingService variableParsingService, VariableValidationService variableValidationService,
                                                               ExtensionsVariablesMappingProvider mappingProvider) {
        return new ProcessVariablesInitiator(processExtensionService, variableParsingService, variableValidationService, mappingProvider);
    }

    @Bean
    @ConditionalOnMissingBean
    public APIProcessInstanceConverter apiProcessInstanceConverter() {
        return new APIProcessInstanceConverter();
    }

    @Bean
    @ConditionalOnMissingBean
    public APIDeploymentConverter apiDeploymentConverter() {
        return new APIDeploymentConverter();
    }

    @Bean
    @ConditionalOnMissingBean
    public ProcessRuntimeConfiguration processRuntimeConfiguration(@Autowired(required = false) List<ProcessRuntimeEventListener<?>> processRuntimeEventListeners,
                                                                   @Autowired(required = false) List<VariableEventListener<?>> variableEventListeners) {
        return new ProcessRuntimeConfigurationImpl(getInitializedListeners(processRuntimeEventListeners), getInitializedListeners(variableEventListeners));
    }

    @Bean
    @ConditionalOnMissingBean
    public ToAPIProcessStartedEventConverter apiProcessStartedEventConverter(APIProcessInstanceConverter processInstanceConverter) {
        return new ToAPIProcessStartedEventConverter(processInstanceConverter);
    }

    @Bean
    public APIProcessDismissElementConverter apiProcessDismissElementConverter() {
        return new APIProcessDismissElementConverter();
    }


    @Bean
    @ConditionalOnMissingBean
    public ToAPIProcessCreatedEventConverter apiProcessCreatedEventConverter(APIProcessInstanceConverter processInstanceConverter) {
        return new ToAPIProcessCreatedEventConverter(processInstanceConverter);
    }

    @Bean
    @ConditionalOnMissingBean
    public ToProcessUpdatedConverter processUpdatedConverter(APIProcessInstanceConverter processInstanceConverter) {
        return new ToProcessUpdatedConverter(processInstanceConverter);
    }

    @Bean
    @ConditionalOnMissingBean
    public ToProcessResumedConverter processResumedConverter(APIProcessInstanceConverter processInstanceConverter) {
        return new ToProcessResumedConverter(processInstanceConverter);
    }

    @Bean
    @ConditionalOnMissingBean
    public ToProcessSuspendedConverter processSuspendedConverter(APIProcessInstanceConverter processInstanceConverter) {
        return new ToProcessSuspendedConverter(processInstanceConverter);
    }

    private <T> List<T> getInitializedListeners(List<T> eventListeners) {
        return eventListeners != null ? eventListeners : emptyList();
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerProcessStartedEventListenerDelegate")
    public InitializingBean registerProcessStartedEventListenerDelegate(RuntimeService runtimeService,
                                                                        @Autowired(required = false) List<ProcessRuntimeEventListener<ProcessStartedEvent>> listeners,
                                                                        ToAPIProcessStartedEventConverter processStartedEventConverter) {
        return () -> runtimeService.addEventListener(new ProcessStartedListenerDelegate(getInitializedListeners(listeners),
                        processStartedEventConverter),
                ActivitiEventType.PROCESS_STARTED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerProcessCreatedEventListenerDelegate")
    public InitializingBean registerProcessCreatedEventListenerDelegate(RuntimeService runtimeService,
                                                                        @Autowired(required = false) List<ProcessRuntimeEventListener<ProcessCreatedEvent>> eventListeners,
                                                                        ToAPIProcessCreatedEventConverter converter) {
        return () -> runtimeService.addEventListener(new ProcessCreatedListenerDelegate(getInitializedListeners(eventListeners),
                        converter),
                ActivitiEventType.ENTITY_CREATED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerProcessUpdatedEventListenerDelegate")
    public InitializingBean registerProcessUpdatedEventListenerDelegate(RuntimeService runtimeService,
                                                                        @Autowired(required = false) List<ProcessRuntimeEventListener<ProcessUpdatedEvent>> eventListeners,
                                                                        ToProcessUpdatedConverter converter) {
        return () -> runtimeService.addEventListener(new ProcessUpdatedListenerDelegate(getInitializedListeners(eventListeners),
                        converter),
                ActivitiEventType.ENTITY_UPDATED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerProcessSuspendedEventListenerDelegate")
    public InitializingBean registerProcessSuspendedEventListenerDelegate(RuntimeService runtimeService,
                                                                          @Autowired(required = false) List<ProcessRuntimeEventListener<ProcessSuspendedEvent>> eventListeners,
                                                                          ToProcessSuspendedConverter converter) {
        return () -> runtimeService.addEventListener(new ProcessSuspendedListenerDelegate(getInitializedListeners(eventListeners),
                        converter),
                ActivitiEventType.ENTITY_SUSPENDED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerProcessResumedEventListenerDelegate")
    public InitializingBean registerProcessResumedEventListenerDelegate(RuntimeService runtimeService,
                                                                        @Autowired(required = false) List<ProcessRuntimeEventListener<ProcessResumedEvent>> eventListeners,
                                                                        ToProcessResumedConverter converter) {
        return () -> runtimeService.addEventListener(new ProcessResumedEventListenerDelegate(getInitializedListeners(eventListeners),
                        converter),
                ActivitiEventType.ENTITY_ACTIVATED);
    }

    @Bean
    @ConditionalOnMissingBean
    public ToProcessCompletedConverter processCompletedConverter(APIProcessInstanceConverter processInstanceConverter) {
        return new ToProcessCompletedConverter(processInstanceConverter);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerProcessCompletedListenerDelegate")
    public InitializingBean registerProcessCompletedListenerDelegate(RuntimeService runtimeService,
                                                                     @Autowired(required = false) List<ProcessRuntimeEventListener<ProcessCompletedEvent>> eventListeners,
                                                                     ToProcessCompletedConverter converter) {
        return () -> runtimeService.addEventListener(new ProcessCompletedListenerDelegate(getInitializedListeners(eventListeners),
                        converter),
                ActivitiEventType.PROCESS_COMPLETED);
    }

    @Bean
    public ProcessRuntimeEventListener<ProcessCompletedEvent> ProcessCompletedClearVarEventListener(HistoryService historyService) {
        return new ProcessClearVarEventListener(historyService);
    }
    @Bean
    public ProcessRuntimeEventListener<ProcessCompletedEvent> ProcessEndEventListener(HistoryService historyService) {
        return new ProcessEndEventListener(historyService);
    }
    @Bean
    @ConditionalOnMissingBean(name = "registerProcessCancelledListenerDelegate")
    public InitializingBean registerProcessCancelledListenerDelegate(RuntimeService runtimeService,
                                                                     APIProcessInstanceConverter processInstanceConverter,
                                                                     @Autowired(required = false) List<ProcessRuntimeEventListener<ProcessCancelledEvent>> eventListeners) {
        return () -> runtimeService.addEventListener(new ProcessCancelledListenerDelegate(getInitializedListeners(eventListeners), new ToProcessCancelledConverter(processInstanceConverter)), ActivitiEventType.PROCESS_CANCELLED);
    }

    @Bean
    @ConditionalOnMissingBean
    public ToActivityConverter activityConverter() {
        return new ToActivityConverter();
    }

    @Bean
    @ConditionalOnMissingBean
    public ToSignalConverter signalConverter() {
        return new ToSignalConverter();
    }

    @Bean
    @ConditionalOnMissingBean
    public BPMNTimerConverter bpmnTimerConveter() {
        return new BPMNTimerConverter();
    }

    @Bean
    @ConditionalOnMissingBean
    public BPMNMessageConverter bpmnMessageConveter() {
        return new BPMNMessageConverter();
    }

    @Bean
    public BPMNErrorConverter bpmnErrorConverter() {
        return new BPMNErrorConverter();
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerActivityStartedListenerDelegate")
    public InitializingBean registerActivityStartedListenerDelegate(RuntimeService runtimeService,
                                                                    @Autowired(required = false) List<BPMNElementEventListener<BPMNActivityStartedEvent>> eventListeners,
                                                                    ToActivityConverter activityConverter) {
        return () -> runtimeService.addEventListener(new ActivityStartedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToActivityStartedConverter(activityConverter)),
                ActivitiEventType.ACTIVITY_STARTED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerActivityCompletedListenerDelegate")
    public InitializingBean registerActivityCompletedListenerDelegate(RuntimeService runtimeService,
                                                                      @Autowired(required = false) List<BPMNElementEventListener<BPMNActivityCompletedEvent>> eventListeners,
                                                                      ToActivityConverter activityConverter) {
        return () -> runtimeService.addEventListener(new ActivityCompletedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToActivityCompletedConverter(activityConverter)),
                ActivitiEventType.ACTIVITY_COMPLETED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerActivityCancelledListenerDelegate")
    public InitializingBean registerActivityCancelledListenerDelegate(RuntimeService runtimeService,
                                                                      @Autowired(required = false) List<BPMNElementEventListener<BPMNActivityCancelledEvent>> eventListeners,
                                                                      ToActivityConverter activityConverter) {
        return () -> runtimeService.addEventListener(new ActivityCancelledListenerDelegate(getInitializedListeners(eventListeners),
                        new ToActivityCancelledConverter(activityConverter)),
                ActivitiEventType.ACTIVITY_CANCELLED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerActivitySignaledListenerDelegate")
    public InitializingBean registerActivitySignaledListenerDelegate(RuntimeService runtimeService,
                                                                     @Autowired(required = false) List<BPMNElementEventListener<BPMNSignalReceivedEvent>> eventListeners,
                                                                     ToSignalConverter signalConverter) {
        return () -> runtimeService.addEventListener(new SignalReceivedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToSignalReceivedConverter(signalConverter)),
                ActivitiEventType.ACTIVITY_SIGNALED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerTimerFiredListenerDelegate")
    public InitializingBean registerTimerFiredListenerDelegate(RuntimeService runtimeService,
                                                               @Autowired(required = false) List<BPMNElementEventListener<BPMNTimerFiredEvent>> eventListeners,
                                                               BPMNTimerConverter bpmnTimerConverter) {
        return () -> runtimeService.addEventListener(new TimerFiredListenerDelegate(getInitializedListeners(eventListeners),
                        new ToTimerFiredConverter(bpmnTimerConverter)),
                ActivitiEventType.TIMER_FIRED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerTimerScheduledListenerDelegate")
    public InitializingBean registerTimerScheduledListenerDelegate(RuntimeService runtimeService,
                                                                   @Autowired(required = false) List<BPMNElementEventListener<BPMNTimerScheduledEvent>> eventListeners,
                                                                   BPMNTimerConverter bpmnTimerConverter) {
        return () -> runtimeService.addEventListener(new TimerScheduledListenerDelegate(getInitializedListeners(eventListeners),
                        new ToTimerScheduledConverter(bpmnTimerConverter)),
                ActivitiEventType.TIMER_SCHEDULED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerTimerCancelledListenerDelegate")
    public InitializingBean registerTimerCancelledListenerDelegate(RuntimeService runtimeService,
                                                                   @Autowired(required = false) List<BPMNElementEventListener<BPMNTimerCancelledEvent>> eventListeners,
                                                                   BPMNTimerConverter bpmnTimerConverter) {
        return () -> runtimeService.addEventListener(new TimerCancelledListenerDelegate(getInitializedListeners(eventListeners),
                        new ToTimerCancelledConverter(bpmnTimerConverter)),
                ActivitiEventType.JOB_CANCELED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerTimerFailedListenerDelegate")
    public InitializingBean registerTimerFailedListenerDelegate(RuntimeService runtimeService,
                                                                @Autowired(required = false) List<BPMNElementEventListener<BPMNTimerFailedEvent>> eventListeners,
                                                                BPMNTimerConverter bpmnTimerConverter) {
        return () -> runtimeService.addEventListener(new TimerFailedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToTimerFailedConverter(bpmnTimerConverter)),
                ActivitiEventType.JOB_EXECUTION_FAILURE);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerTimerExecutedListenerDelegate")
    public InitializingBean registerTimerExecutedListenerDelegate(RuntimeService runtimeService,
                                                                  @Autowired(required = false) List<BPMNElementEventListener<BPMNTimerExecutedEvent>> eventListeners,
                                                                  BPMNTimerConverter bpmnTimerConverter) {
        return () -> runtimeService.addEventListener(new TimerExecutedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToTimerExecutedConverter(bpmnTimerConverter)),
                ActivitiEventType.JOB_EXECUTION_SUCCESS);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerTimerRetriesDecrementedListenerDelegate")
    public InitializingBean registerTimerRetriesDecrementedListenerDelegate(RuntimeService runtimeService,
                                                                            @Autowired(required = false) List<BPMNElementEventListener<BPMNTimerRetriesDecrementedEvent>> eventListeners,
                                                                            BPMNTimerConverter bpmnTimerConverter) {
        return () -> runtimeService.addEventListener(new TimerRetriesDecrementedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToTimerRetriesDecrementedConverter(bpmnTimerConverter)),
                ActivitiEventType.JOB_RETRIES_DECREMENTED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerMessageSentListenerDelegate")
    public InitializingBean registerMessageSentListenerDelegate(RuntimeService runtimeService,
                                                                @Autowired(required = false) List<BPMNElementEventListener<BPMNMessageSentEvent>> eventListeners,
                                                                BPMNMessageConverter bpmnMessageConverter) {
        return () -> runtimeService.addEventListener(new MessageSentListenerDelegate(getInitializedListeners(eventListeners),
                        new ToMessageSentConverter(bpmnMessageConverter)),
                ActivitiEventType.ACTIVITY_MESSAGE_SENT);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerMessageReceivedListenerDelegate")
    public InitializingBean registerMessageReceivedListenerDelegate(RuntimeService runtimeService,
                                                                    @Autowired(required = false) List<BPMNElementEventListener<BPMNMessageReceivedEvent>> eventListeners,
                                                                    BPMNMessageConverter bpmnMessageConverter) {
        return () -> runtimeService.addEventListener(new MessageReceivedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToMessageReceivedConverter(bpmnMessageConverter)),
                ActivitiEventType.ACTIVITY_MESSAGE_RECEIVED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerMessageWaitingListenerDelegate")
    public InitializingBean registerMessageWaitingListenerDelegate(RuntimeService runtimeService,
                                                                   @Autowired(required = false) List<BPMNElementEventListener<BPMNMessageWaitingEvent>> eventListeners,
                                                                   BPMNMessageConverter bpmnMessageConverter) {
        return () -> runtimeService.addEventListener(new MessageWaitingListenerDelegate(getInitializedListeners(eventListeners),
                        new ToMessageWaitingConverter(bpmnMessageConverter)),
                ActivitiEventType.ACTIVITY_MESSAGE_WAITING);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerSequenceFlowTakenListenerDelegate")
    public InitializingBean registerSequenceFlowTakenListenerDelegate(RuntimeService runtimeService,
                                                                      @Autowired(required = false) List<BPMNElementEventListener<BPMNSequenceFlowTakenEvent>> eventListeners) {
        return () -> runtimeService.addEventListener(new SequenceFlowTakenListenerDelegate(getInitializedListeners(eventListeners),
                        new ToSequenceFlowTakenConverter()),
                ActivitiEventType.SEQUENCEFLOW_TAKEN);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerErrorReceviedListenerDelegate")
    public InitializingBean registerErrorReceviedListenerDelegate(RuntimeService runtimeService,
                                                                  @Autowired(required = false) List<BPMNElementEventListener<BPMNErrorReceivedEvent>> eventListeners,
                                                                  BPMNErrorConverter bpmnErrorConverter) {
        return () -> runtimeService.addEventListener(new ErrorReceivedListenerDelegate(getInitializedListeners(eventListeners),
                        new ToErrorReceivedConverter(bpmnErrorConverter)),
                ActivitiEventType.ACTIVITY_ERROR_RECEIVED);
    }

    @Bean
    @ConditionalOnMissingBean(name = "registerMessageSubscriptionCancelledListenerDelegate")
    public InitializingBean registerMessageSubscriptionCancelledListenerDelegate(RuntimeService runtimeService,
                                                                                 @Autowired(required = false) List<ProcessRuntimeEventListener<MessageSubscriptionCancelledEvent>> eventListeners,
                                                                                 MessageSubscriptionConverter converter) {
        return () -> runtimeService.addEventListener(new MessageSubscriptionCancelledListenerDelegate(getInitializedListeners(eventListeners),
                        new ToMessageSubscriptionCancelledConverter(converter)),
                ActivitiEventType.ENTITY_DELETED);
    }
}
